package com.learn.concurrent;

/**
 * @author wangxing
 * @version 2020/8/10 9:43 Administrator
 */
public class LearnVolatile {
    private static class T{
        volatile long x=0L;
    }
    static final long COUNT = 10_000_000L;
    static T[] tArr = new T[2];
    static{
        tArr[0]=new T();
        tArr[1]=new T();
    }

    public static void main(String[] args) {
        cacheLine2();
        cacheLine1();
    }
    /**
     * 数据更新时不跨缓存行,在一行内更新
     * 验证方式,因使用volatile关键字进行标注,会使得每次x的更新都被通知到内存更新缓存行
     * 而数组中两个内容在内存中是连续的,两个线程更新数据时会相互通知对方重新获取缓存行内容,导致数据更新效率变低
     */
    public static void  cacheLine1(){
        long  start = System.currentTimeMillis();
        Thread thread =new Thread(()->{
            int i=0;
            while (i++<COUNT)tArr[0].x=i;
        });
        Thread thread1 = new Thread(() -> {
            int i=0;
            while (i++<COUNT)tArr[0].x=i;
        });
        thread.start();
        thread1.start();
        try {
            thread.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis()-start+" 1");
    }
   private static class P{
//        8个long类型是8字节正好一个缓存行大小
        long a1,a2,a3,a4,a5,a6,a7;
    }
    private static class P2 extends P{
       volatile long x=0;
    }

   static volatile P2[] pArr =new P2[2];
   static{
       pArr[0] = new P2();
       pArr[1] = new P2();
   }
    /**
     * 数据更新时分多个缓存行,不再同一个行内更新
     * 验证方式,因使用volatile关键字进行标注,会使得每次x的更新都被通知到内存更新缓存行
     * 而数组中两个内容在内存中是连续的,但是现在数组中P是超过一个缓存行大小的,所以更新的时候不会让另一个线程进行更新,这样会提升效率,减少缓存行更新次数
     */
    public static void  cacheLine2(){
        long  start = System.currentTimeMillis();
        Thread thread =new Thread(()->{
            int i=0;
            while (i++<COUNT)pArr[0].x=i;
        });
        Thread thread1 = new Thread(() -> {
            int i=0;
            while (i++<COUNT)pArr[1].x=i;
        });
        thread.start();
        thread1.start();
        try {
            thread.join();
            thread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis()-start+" 2");
    }
}
